home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / yacc.arc / Y2.C < prev    next >
Text File  |  1985-09-04  |  20KB  |  867 lines

  1. #include "c:dextern"
  2. #define IDENTIFIER 257
  3. #define MARK 258
  4. #define TERM 259
  5. #define LEFT 260
  6. #define RIGHT 261
  7. #define BINARY 262
  8. #define PREC 263
  9. #define LCURLY 264
  10. #define C_IDENTIFIER 265  /* name followed by colon */
  11. #define NUMBER 266
  12. #define START 267
  13. #define TYPEDEF 268
  14. #define TYPENAME 269
  15. #define UNION 270
  16. #define ENDFILE 0
  17.  
  18.     /* communication variables between various I/O routines */
  19.  
  20. char *infile;    /* input file name */
  21. int numbval;    /* value of an input number */
  22. char tokname[NAMESIZE];    /* input token name */
  23.  
  24.     /* storage of names */
  25.  
  26. char cnames[CNAMSZ];    /* place where token and nonterminal names are stored */
  27. int cnamsz = CNAMSZ;    /* size of cnames */
  28. char * cnamp = cnames;    /* place where next name is to be put in */
  29. int ndefout = 3;  /* number of defined symbols output */
  30.  
  31.     /* storage of types */
  32. int ntypes;    /* number of types defined */
  33. char * typeset[NTYPES];    /* pointers to type tags */
  34.  
  35.     /* symbol tables for tokens and nonterminals */
  36.  
  37. int ntokens = 0;
  38. struct toksymb tokset[NTERMS];
  39. int toklev[NTERMS];
  40. int nnonter = -1;
  41. struct ntsymb nontrst[NNONTERM];
  42. int start;    /* start symbol */
  43.  
  44.     /* assigned token type values */
  45. int extval = 0;
  46.  
  47.     /* input and output file descriptors */
  48.  
  49. FILE * finput;        /* yacc input file */
  50. FILE * faction;        /* file for saving actions */
  51. FILE * fdefine;        /* file for #defines */
  52. FILE * ftable;        /* y.tab.c file */
  53. FILE * ftemp;        /* tempfile to pass 2 */
  54. FILE * foutput;        /* y.output file */
  55.  
  56.     /* storage for grammar rules */
  57.  
  58. int mem0[MEMSIZE] ; /* production storage */
  59. int *mem = mem0;
  60. int nprod= 1;    /* number of productions */
  61. int *prdptr[NPROD];    /* pointers to descriptions of productions */
  62. int levprd[NPROD] ;    /* precedence levels for the productions */
  63.  
  64.  
  65. setup(argc,argv) int argc; char *argv[];
  66. {    int i,j,lev,t, ty;
  67.     int c;
  68.     int *p;
  69.     char actname[8];
  70.  
  71.     foutput = NULL;
  72.     fdefine = NULL;
  73.     i = 1;
  74.     while( argc >= 2  && argv[1][0] == '-' ) {
  75.         while( *++(argv[1]) ){
  76.             switch( *argv[1] ){
  77.             case 'v':
  78.             case 'V':
  79.                 foutput = fopen(FILEU, "w" );
  80.                 if( foutput == NULL ) error( "cannot open y.output" );
  81.                 continue;
  82.             case 'D':
  83.             case 'd':
  84.                 fdefine = fopen( FILED, "w" );
  85.                 continue;
  86.             case 'o':
  87.             case 'O':
  88.                 fprintf( stderr, "`o' flag now default in yacc\n" );
  89.                 continue;
  90.  
  91.             case 'r':
  92.             case 'R':
  93.                 error( "Ratfor Yacc is dead: sorry...\n" );
  94.  
  95.             default:
  96.                 error( "illegal option: %c", *argv[1]);
  97.                 }
  98.             }
  99.         argv++;
  100.         argc--;
  101.         }
  102.  
  103.     ftable = fopen( OFILE, "w" );
  104.     if( ftable == NULL ) error( "cannot open table file" );
  105.  
  106.     ftemp = fopen( TEMPNAME, "w" );
  107.     faction = fopen( ACTNAME, "w" );
  108.     if( ftemp==NULL || faction==NULL ) error( "cannot open temp file" );
  109.  
  110.     if( argc < 2 || ((finput=fopen( infile=argv[1], "r" )) == NULL ) ){
  111.         error( "cannot open input file" );
  112.         }
  113.  
  114.     cnamp = cnames;
  115.     defin(0,"$end");
  116.     extval = 0400;
  117.     defin(0,"error");
  118.     defin(1,"$accept");
  119.     mem=mem0;
  120.     lev = 0;
  121.     ty = 0;
  122.     i=0;
  123.  
  124.     /* sorry -- no yacc parser here.....
  125.         we must bootstrap somehow... */
  126.  
  127.     for( t=gettok();  t!=MARK && t!= ENDFILE; ){
  128.         switch( t ){
  129.  
  130.         case ';':
  131.             t = gettok();
  132.             break;
  133.  
  134.         case START:
  135.             if( (t=gettok()) != IDENTIFIER ){
  136.                 error( "bad %%start construction" );
  137.                 }
  138.             start = chfind(1,tokname);
  139.             t = gettok();
  140.             continue;
  141.  
  142.         case TYPEDEF:
  143.             if( (t=gettok()) != TYPENAME ) error( "bad syntax in %%type" );
  144.             ty = numbval;
  145.             for(;;){
  146.                 t = gettok();
  147.                 switch( t ){
  148.  
  149.                 case IDENTIFIER:
  150.                     if( (t=chfind( 1, tokname ) ) < NTBASE ) {
  151.                         j = TYPE( toklev[t] );
  152.                         if( j!= 0 && j != ty ){
  153.                             error( "type redeclaration of token %s",
  154.                                 tokset[t].name );
  155.                             }
  156.                         else SETTYPE( toklev[t],ty);
  157.                         }
  158.                     else {
  159.                         j = nontrst[t-NTBASE].tvalue;
  160.                         if( j != 0 && j != ty ){
  161.                             error( "type redeclaration of nonterminal %s",
  162.                                 nontrst[t-NTBASE].name );
  163.                             }
  164.                         else nontrst[t-NTBASE].tvalue = ty;
  165.                         }
  166.                 case ',':
  167.                     continue;
  168.  
  169.                 case ';':
  170.                     t = gettok();
  171.                     break;
  172.                 default:
  173.                     break;
  174.                     }
  175.                 break;
  176.                 }
  177.             continue;
  178.  
  179.         case UNION:
  180.             /* copy the union declaration to the output */
  181.             cpyunion();
  182.             t = gettok();
  183.             continue;
  184.  
  185.         case LEFT:
  186.         case BINARY:
  187.         case RIGHT:
  188.             ++i;
  189.         case TERM:
  190.             lev = t-TERM;  /* nonzero means new prec. and assoc. */
  191.             ty = 0;
  192.  
  193.             /* get identifiers so defined */
  194.  
  195.             t = gettok();
  196.             if( t == TYPENAME ){ /* there is a type defined */
  197.                 ty = numbval;
  198.                 t = gettok();
  199.                 }
  200.  
  201.             for(;;) {
  202.                 switch( t ){
  203.  
  204.                 case ',':
  205.                     t = gettok();
  206.                     continue;
  207.  
  208.                 case ';':
  209.                     break;
  210.  
  211.                 case IDENTIFIER:
  212.                     j = chfind(0,tokname);
  213.                     if( lev ){
  214.                         if( ASSOC(toklev[j]) ) error( "redeclaration of precedence of %s", tokname );
  215.                         SETASC(toklev[j],lev);
  216.                         SETPLEV(toklev[j],i);
  217.                         }
  218.                     if( ty ){
  219.                         if( TYPE(toklev[j]) ) error( "redeclaration of type of %s", tokname );
  220.                         SETTYPE(toklev[j],ty);
  221.                         }
  222.                     if( (t=gettok()) == NUMBER ){
  223.                         tokset[j].value = numbval;
  224.                         if( j < ndefout && j>2 ){
  225.                             error( "please define type number of %s earlier",
  226.                                 tokset[j].name );
  227.                             }
  228.                         t=gettok();
  229.                         }
  230.                     continue;
  231.  
  232.                     }
  233.  
  234.                 break;
  235.                 }
  236.  
  237.             continue;
  238.  
  239.         case LCURLY:
  240.             defout();
  241.             cpycode();
  242.             t = gettok();
  243.             continue;
  244.  
  245.         default:
  246.             error( "syntax error" );
  247.  
  248.             }
  249.  
  250.         }
  251.  
  252.     if( t == ENDFILE ){
  253.         error( "unexpected EOF before %%" );
  254.         }
  255.  
  256.     /* t is MARK */
  257.  
  258.     defout();
  259.  
  260.         fprintf( ftable,  "#define yyclearin yychar = -1\n" );
  261.         fprintf( ftable,  "#define yyerrok yyerrflag = 0\n" );
  262.         fprintf( ftable,  "extern int yychar;\nextern short yyerrflag;\n" );
  263.         fprintf( ftable,  "#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 150\n#endif\n" );
  264.         if( !ntypes ) fprintf( ftable,  "#ifndef YYSTYPE\n#define YYSTYPE int\n#endif\n" );
  265.         fprintf( ftable,  "YYSTYPE yylval, yyval;\n" );
  266.  
  267.     prdptr[0]=mem;
  268.     /* added production */
  269.     *mem++ = NTBASE;
  270.     *mem++ = start;  /* if start is 0, we will overwrite with the lhs of the first rule */
  271.     *mem++ = 1;
  272.     *mem++ = 0;
  273.     prdptr[1]=mem;
  274.  
  275.     while( (t=gettok()) == LCURLY ) cpycode();
  276.  
  277.     if( t != C_IDENTIFIER ) error( "bad syntax on first rule" );
  278.  
  279.     if( !start ) prdptr[0][1] = chfind(1,tokname);
  280.  
  281.     /* read rules */
  282.  
  283.     while( t!=MARK && t!=ENDFILE ){
  284.  
  285.         /* process a rule */
  286.  
  287.         if( t == '|' ){
  288.             *mem++ = *prdptr[nprod-1];
  289.             }
  290.         else if( t == C_IDENTIFIER ){
  291.             *mem = chfind(1,tokname);
  292.             if( *mem < NTBASE ) error( "token illegal on LHS of grammar rule" );
  293.             ++mem;
  294.             }
  295.         else error( "illegal rule: missing semicolon or | ?" );
  296.  
  297.         /* read rule body */
  298.  
  299.  
  300.         t = gettok();
  301.     more_rule:
  302.         while( t == IDENTIFIER ) {
  303.             *mem = chfind(1,tokname);
  304.             if( *mem<NTBASE ) levprd[nprod] = toklev[*mem];
  305.             ++mem;
  306.             t = gettok();
  307.             }
  308.  
  309.  
  310.         if( t == PREC ){
  311.             if( gettok()!=IDENTIFIER) error( "illegal %%prec syntax" );
  312.             j = chfind(2,tokname);
  313.             if( j>=NTBASE)error("nonterminal %s illegal after %%prec", nontrst[j-NTBASE].name);
  314.             levprd[nprod]=toklev[j];
  315.             t = gettok();
  316.             }
  317.  
  318.         if( t == '=' ){
  319.             levprd[nprod] |= ACTFLAG;
  320.             fprintf( faction, "\ncase %d:", nprod );
  321.             cpyact( mem-prdptr[nprod]-1 );
  322.             fprintf( faction, " break;" );
  323.             if( (t=gettok()) == IDENTIFIER ){
  324.                 /* action within rule... */
  325.  
  326.                 sprintf( actname, "$$%d", nprod );
  327.                 j = chfind(1,actname);  /* make it a nonterminal */
  328.  
  329.                 /* the current rule will become rule number nprod+1 */
  330.                 /* move the contents down, and make room for the null */
  331.  
  332.                 for( p=mem; p>=prdptr[nprod]; --p ) p[2] = *p;
  333.                 mem += 2;
  334.  
  335.                 /* enter null production for action */
  336.  
  337.                 p = prdptr[nprod];
  338.  
  339.                 *p++ = j;
  340.                 *p++ = -nprod;
  341.  
  342.                 /* update the production information */
  343.  
  344.                 levprd[nprod+1] = levprd[nprod] & ~ACTFLAG;
  345.                 levprd[nprod] = ACTFLAG;
  346.  
  347.                 if( ++nprod >= NPROD ) error( "more than %d rules", NPROD );
  348.                 prdptr[nprod] = p;
  349.  
  350.                 /* make the action appear in the original rule */
  351.                 *mem++ = j;
  352.  
  353.                 /* get some more of the rule */
  354.  
  355.                 goto more_rule;
  356.                 }
  357.  
  358.             }
  359.  
  360.         while( t == ';' ) t = gettok();
  361.  
  362.         *mem++ = -nprod;
  363.  
  364.         /* check that default action is reasonable */
  365.  
  366.         if( ntypes && !(levprd[nprod]&ACTFLAG) && nontrst[*prdptr[nprod]-NTBASE].tvalue ){
  367.             /* no explicit action, LHS has value */
  368.             register tempty;
  369.             tempty = prdptr[nprod][1];
  370.             if( tempty < 0 ) error( "must return a value, since LHS has a type" );
  371.             else if( tempty >= NTBASE ) tempty = nontrst[tempty-NTBASE].tvalue;
  372.             else tempty = TYPE( toklev[tempty] );
  373.             if( tempty != nontrst[*prdptr[nprod]-NTBASE].tvalue ){
  374.                 error( "default action causes potential type clash" );
  375.                 }
  376.             }
  377.  
  378.         if( ++nprod >= NPROD ) error( "more than %d rules", NPROD );
  379.         prdptr[nprod] = mem;
  380.         levprd[nprod]=0;
  381.  
  382.         }
  383.  
  384.     /* end of all rules */
  385.  
  386.     finact();
  387.     if( t == MARK ){
  388.         fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
  389.         while( (c=getc(finput)) != EOF ) putc( c, ftable );
  390.         }
  391.     fclose( finput );
  392.     }
  393.  
  394. finact(){
  395.     /* finish action routine */
  396.  
  397.     fclose(faction);
  398.  
  399.     fprintf( ftable, "# define YYERRCODE %d\n", tokset[2].value );
  400.  
  401.     }
  402.  
  403. defin( t, s ) register char  *s; {
  404. /*    define s to be a terminal if t=0
  405.     or a nonterminal if t=1        */
  406.  
  407.     register val;
  408.  
  409.     if (t) {
  410.         if( ++nnonter >= NNONTERM ) error("too many nonterminals, limit %d",NNONTERM);
  411.         nontrst[nnonter].name = cstash(s);
  412.         return( NTBASE + nnonter );
  413.         }
  414.     /* must be a token */
  415.     if( ++ntokens >= NTERMS ) error("too many terminals, limit %d",NTERMS );
  416.     tokset[ntokens].name = cstash(s);
  417.  
  418.     /* establish value for token */
  419.  
  420.     if( s[0]==' ' && s[2]=='\0' ) /* single character literal */
  421.         val = s[1];
  422.     else if ( s[0]==' ' && s[1]=='\\' ) { /* escape sequence */
  423.         if( s[3] == '\0' ){ /* single character escape sequence */
  424.             switch ( s[2] ){
  425.                      /* character which is escaped */
  426.             case 'n': val = '\n'; break;
  427.             case 'r': val = '\r'; break;
  428.             case 'b': val = '\b'; break;
  429.             case 't': val = '\t'; break;
  430.             case 'f': val = '\f'; break;
  431.             case '\'': val = '\''; break;
  432.             case '"': val = '"'; break;
  433.             case '\\': val = '\\'; break;
  434.             default: error( "invalid escape" );
  435.                 }
  436.             }
  437.         else if( s[2] <= '7' && s[2]>='0' ){ /* \nnn sequence */
  438.             if( s[3]<'0' || s[3] > '7' || s[4]<'0' ||
  439.                 s[4]>'7' || s[5] != '\0' ) error("illegal \\nnn construction" );
  440.             val = 64*s[2] + 8*s[3] + s[4] - 73*'0';
  441.             if( val == 0 ) error( "'\\000' is illegal" );
  442.             }
  443.         }
  444.     else {
  445.         val = extval++;
  446.         }
  447.     tokset[ntokens].value = val;
  448.     toklev[ntokens] = 0;
  449.     return( ntokens );
  450.     }
  451.  
  452. defout(){ /* write out the defines (at the end of the declaration section) */
  453.  
  454.     register int i, c;
  455.     register char *cp;
  456.  
  457.     for( i=ndefout; i<=ntokens; ++i ){
  458.  
  459.         cp = tokset[i].name;
  460.         if( *cp == ' ' ) ++cp;  /* literals */
  461.  
  462.         for( ; (c= *cp)!='\0'; ++cp ){
  463.  
  464.             if( islower(c) || isupper(c) || isdigit(c) || c=='_' ); 
  465.  /* VOID */
  466.             else goto nodef;
  467.             }
  468.  
  469.         fprintf( ftable, "# efine %s %d\n", tokset[i].name, tokset[i].value );
  470.         if( fdefine != NULL ) fprintf( fdefine, "# define %s %d\n", tokset[i].name, tokset[i].value );
  471.  
  472.     nodef:    ;
  473.         }
  474.  
  475.     ndefout = ntokens+1;
  476.  
  477.     }
  478.  
  479. char *
  480. cstash( s ) register char *s; {
  481.     char *temp;
  482.  
  483.     temp = cnamp;
  484.     do {
  485.         if( cnamp >= &cnames[cnamsz] ) error("too many characters in id's and literals" );
  486.         else *cnamp++ = *s;
  487.         }  while ( *s++ );
  488.     return( temp );
  489.     }
  490.  
  491. gettok() {
  492.     register i, base;
  493.     static int peekline; /* number of '\n' seen in lookahead */
  494.     register c, match, reserve;
  495.  
  496. begin:
  497.     reserve = 0;
  498.     lineno += peekline;
  499.     peekline = 0;
  500.     c = getc(finput);
  501.     while( c==' ' || c=='\n' || c=='\t' || c=='\f' ){
  502.         if( c == '\n' ) ++lineno;
  503.         c=getc(finput);
  504.         }
  505.     if( c == '/' ){ /* skip comment */
  506.         lineno += skipcom();
  507.         goto begin;
  508.         }
  509.  
  510.     switch(c){
  511.  
  512.     case EOF:
  513.         return(ENDFILE);
  514.     case '{':
  515.         ungetc( c, finput );
  516.         return( '=' );  /* action ... */
  517.     case '<':  /* get, and look up, a type name (union member name) */
  518.         i = 0;
  519.         while( (c=getc(finput)) != '>' && c>=0 && c!= '\n' ){
  520.             tokname[i] = c;
  521.             if( ++i >= NAMESIZE ) --i;
  522.             }
  523.         if( c != '>' ) error( "unterminated < ... > clause" );
  524.         tokname[i] = '\0';
  525.         for( i=1; i<=ntypes; ++i ){
  526.             if( !strcmp( typeset[i], tokname ) ){
  527.                 numbval = i;
  528.                 return( TYPENAME );
  529.                 }
  530.             }
  531.         typeset[numbval = ++ntypes] = cstash( tokname );
  532.         return( TYPENAME );
  533.  
  534.     case '"':    
  535.     case '\'':
  536.         match = c;
  537.         tokname[0] = ' ';
  538.         i = 1;
  539.         for(;;){
  540.             c = getc(finput);
  541.             if( c == '\n' || c == EOF )
  542.                 error("illegal or missing ' or \"" );
  543.             if( c == '\\' ){
  544.                 c = getc(finput);
  545.                 tokname[i] = '\\';
  546.                 if( ++i >= NAMESIZE ) --i;
  547.                 }
  548.             else if( c == match ) break;
  549.             tokname[i] = c;
  550.             if( ++i >= NAMESIZE ) --i;
  551.             }
  552.         break;
  553.  
  554.     case '%':
  555.     case '\\':
  556.  
  557.         switch(c=getc(finput)) {
  558.  
  559.         case '0':    return(TERM);
  560.         case '<':    return(LEFT);
  561.         case '2':    return(BINARY);
  562.         case '>':    return(RIGHT);
  563.         case '%':
  564.         case '\\':    return(MARK);
  565.         case '=':    return(PREC);
  566.         case '{':    return(LCURLY);
  567.         default:    reserve = 1;
  568.             }
  569.  
  570.     default:
  571.  
  572.         if( isdigit(c) ){ /* number */
  573.             numbval = c-'0' ;
  574.             base = (c=='0') ? 8 : 10 ;
  575.             for( c=getc(finput); isdigit(c) ; c=getc(finput) ){
  576.                 numbval = numbval*base + c - '0';
  577.                 }
  578.             ungetc( c, finput );
  579.             return(NUMBER);
  580.             }
  581.         else if( islower(c) || isupper(c) || c=='_' || c=='.' || c=='$' ){
  582.             i = 0;
  583.             while( islower(c) || isupper(c) || isdigit(c) || c=='_' || c=='.' || c=='$' ){
  584.                 tokname[i] = c;
  585.                 if( reserve && isupper(c) ) tokname[i] += 'a'-'A';
  586.                 if( ++i >= NAMESIZE ) --i;
  587.                 c = getc(finput);
  588.                 }
  589.             }
  590.         else return(c);
  591.  
  592.         ungetc( c, finput );
  593.         }
  594.  
  595.     tokname[i] = '\0';
  596.  
  597.     if( reserve ){ /* find a reserved word */
  598.         if( !strcmp(tokname,"term")) return( TERM );
  599.         if( !strcmp(tokname,"token")) return( TERM );
  600.         if( !strcmp(tokname,"left")) return( LEFT );
  601.         if( !strcmp(tokname,"nonassoc")) return( BINARY );
  602.         if( !strcmp(tokname,"binary")) return( BINARY );
  603.         if( !strcmp(tokname,"right")) return( RIGHT );
  604.         if( !strcmp(tokname,"prec")) return( PREC );
  605.         if( !strcmp(tokname,"start")) return( START );
  606.         if( !strcmp(tokname,"type")) return( TYPEDEF );
  607.         if( !strcmp(tokname,"union")) return( UNION );
  608.         error("invalid escape, or illegal reserved word: %s", tokname );
  609.         }
  610.  
  611.     /* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */
  612.  
  613.     c = getc(finput);
  614.     while( c==' ' || c=='\t'|| c=='\n' || c=='\f' || c== '/' ) {
  615.         if( c == '\n' ) ++peekline;
  616.         else if( c == '/' ){ /* look for comments */
  617.             peekline += skipcom();
  618.             }
  619.         c = getc(finput);
  620.         }
  621.     if( c == ':' ) return( C_IDENTIFIER );
  622.     ungetc( c, finput );
  623.     return( IDENTIFIER );
  624. }
  625.  
  626. fdtype( t ){ /* determine the type of a symbol */
  627.     register v;
  628.     if( t >= NTBASE ) v = nontrst[t-NTBASE].tvalue;
  629.     else v = TYPE( toklev[t] );
  630.     if( v <= 0 ) error( "must specify type for %s", (t>=NTBASE)?nontrst[t-NTBASE].name:
  631.             tokset[t].name );
  632.     return( v );
  633.     }
  634.  
  635. chfind( t, s ) register char *s; {
  636.     int i;
  637.  
  638.     if (s[0]==' ')t=0;
  639.     TLOOP(i){
  640.         if(!strcmp(s,tokset[i].name)){
  641.             return( i );
  642.             }
  643.         }
  644.     NTLOOP(i){
  645.         if(!strcmp(s,nontrst[i].name)) {
  646.             return( i+NTBASE );
  647.             }
  648.         }
  649.     /* cannot find name */
  650.     if( t>1 )
  651.         error( "%s should have been defined earlier", s );
  652.     return( defin( t, s ) );
  653.     }
  654.  
  655. cpyunion(){
  656.     /* copy the union declaration to the output, and the define file if present */
  657.  
  658.     int level, c;
  659.     fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
  660.     fprintf( ftable, "typedef union " );
  661.     if( fdefine ) fprintf( fdefine, "\ntypedef union " );
  662.  
  663.     level = 0;
  664.     for(;;){
  665.         if( (c=getc(finput)) < 0 ) error( "EOF encountered while processing %%union" );
  666.         putc( c, ftable );
  667.         if( fdefine ) putc( c, fdefine );
  668.  
  669.         switch( c ){
  670.  
  671.         case '\n':
  672.             ++lineno;
  673.             break;
  674.  
  675.         case '{':
  676.             ++level;
  677.             break;
  678.  
  679.         case '}':
  680.             --level;
  681.             if( level == 0 ) { /* we are finished copying */
  682.                 fprintf( ftable, " YYSTYPE;\n" );
  683.                 if( fdefine ) fprintf( fdefine, " YYSTYPE;\nextern YYSTYPE yylval;\n" );
  684.                 return;
  685.                 }
  686.             }
  687.         }
  688.     }
  689.  
  690. cpycode(){ /* copies code between \{ and \} */
  691.  
  692.     int c;
  693.     c = getc(finput);
  694.     if( c == '\n' ) {
  695.         c = getc(finput);
  696.         lineno++;
  697.         }
  698.     fprintf( ftable, "\n# line %d \"%s\"\n", lineno, infile );
  699.     while( c>=0 ){
  700.         if( c=='\\' )
  701.             if( (c=getc(finput)) == '}' ) return;
  702.             else putc('\\', ftable );
  703.         if( c=='%' )
  704.             if( (c=getc(finput)) == '}' ) return;
  705.             else putc('%', ftable );
  706.         putc( c , ftable );
  707.         if( c == '\n' ) ++lineno;
  708.         c = getc(finput);
  709.         }
  710.     error("eof before %%}" );
  711.     }
  712.  
  713. skipcom(){ /* skip over comments */
  714.     register c, i=0;  /* i is the number of lines skipped */
  715.  
  716.     /* skipcom is called after reading a / */
  717.  
  718.     if( getc(finput) != '*' ) error( "illegal comment" );
  719.     c = getc(finput);
  720.     while( c != EOF ){
  721.         while( c == '*' ){
  722.             if( (c=getc(finput)) == '/' ) return( i );
  723.             }
  724.         if( c == '\n' ) ++i;
  725.         c = getc(finput);
  726.         }
  727.     error( "EOF inside comment" );
  728.     /* NOTREACHED */
  729.     }
  730.  
  731. cpyact(offset){ /* copy C action to the next ; or closing } */
  732.     int brac, c, match, j, s, tok;
  733.  
  734.     fprintf( faction, "\n# line %d \"%s\"\n", lineno, infile );
  735.  
  736.     brac = 0;
  737.  
  738. loop:
  739.     c = getc(finput);
  740. swt:
  741.     switch( c ){
  742.  
  743. case ';':
  744.         if( brac == 0 ){
  745.             putc( c , faction );
  746.             return;
  747.             }
  748.         goto lcopy;
  749.  
  750. case '{':
  751.         brac++;
  752.         goto lcopy;
  753.  
  754. case '$':
  755.         s = 1;
  756.         tok = -1;
  757.         c = getc(finput);
  758.         if( c == '<' ){ /* type description */
  759.             ungetc( c, finput );
  760.             if( gettok() != TYPENAME ) error( "bad syntax on $<ident> clause" );
  761.             tok = numbval;
  762.             c = getc(finput);
  763.             }
  764.         if( c == '$' ){
  765.             fprintf( faction, "yyval");
  766.             if( ntypes ){ /* put out the proper tag... */
  767.                 if( tok < 0 ) tok = fdtype( *prdptr[nprod] );
  768.                 fprintf( faction, ".%s", typeset[tok] );
  769.                 }
  770.             goto loop;
  771.             }
  772.         if( c == '-' ){
  773.             s = -s;
  774.             c = getc(finput);
  775.             }
  776.         if( isdigit(c) ){
  777.             j=0;
  778.             while( isdigit(c) ){
  779.                 j= j*10+c-'0';
  780.                 c = getc(finput);
  781.                 }
  782.  
  783.             j = j*s - offset;
  784.             if( j > 0 ){
  785.                 error( "Illegal use of $%d", j+offset );
  786.                 }
  787.  
  788.             fprintf( faction, "yypvt[-%d]", -j );
  789.             if( ntypes ){ /* put out the proper tag */
  790.                 if( j+offset <= 0 && tok < 0 ) error( "must specify type of $%d", j+offset );
  791.                 if( tok < 0 ) tok = fdtype( prdptr[nprod][j+offset] );
  792.                 fprintf( faction, ".%s", typeset[tok] );
  793.                 }
  794.             goto swt;
  795.             }
  796.         putc( '$' , faction );
  797.         if( s<0 ) putc('-', faction );
  798.         goto swt;
  799.  
  800. case '}':
  801.         if( --brac ) goto lcopy;
  802.         putc( c, faction );
  803.         return;
  804.  
  805.  
  806. case '/':    /* look for comments */
  807.         putc( c , faction );
  808.         c = getc(finput);
  809.         if( c != '*' ) goto swt;
  810.  
  811.         /* it really is a comment */
  812.  
  813.         putc( c , faction );
  814.         c = getc(finput);
  815.         while( c != EOF ){
  816.             while( c=='*' ){
  817.                 putc( c , faction );
  818.                 if( (c=getc(finput)) == '/' ) goto lcopy;
  819.                 }
  820.             putc( c , faction );
  821.             if( c == '\n' )++lineno;
  822.             c = getc(finput);
  823.             }
  824.         error( "EOF inside comment" );
  825.  
  826. case '\'':    /* character constant */
  827.         match = '\'';
  828.         goto string;
  829.  
  830. case '"':    /* character string */
  831.         match = '"';
  832.  
  833.     string:
  834.  
  835.         putc( c , faction );
  836.         while( c=getc(finput) ){
  837.  
  838.             if( c=='\\' ){
  839.                 putc( c , faction );
  840.                 c=getc(finput);
  841.                 if( c == '\n' ) ++lineno;
  842.                 }
  843.             else if( c==match ) goto lcopy;
  844.             else if( c=='\n' ) error( "newline in string or char. const." );
  845.             putc( c , faction );
  846.             }
  847.         error( "EOF in string or character constant" );
  848.  
  849. case EOF:
  850.         error("action does not terminate" );
  851.  
  852. case '\n':    ++lineno;
  853.         goto lcopy;
  854.  
  855.         }
  856.  
  857. lcopy:
  858.     putc( c , faction );
  859.     goto loop;
  860.     }
  861.  
  862.  
  863.  
  864.  
  865.  
  866.  
  867.